﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using log4net;
using Newtonsoft.Json;
using RemotingLibs;
using RemotingLibs.QuoteClass;
using TdxApiPool.Common;
using TdxApiPool.Common.Extend;
using TdxApiPool.Connect;
using TdxApiPool.ErrorHandler;
using TdxApiPool.Invoker;
using TdxApiPool.Looper;
using TdxApiPool.Task;

namespace TdxApiPool
{
    public class SanpshootService
    {
        private readonly ILog _log = LogManager.GetLogger(typeof(SanpshootService));

        public static readonly ConcurrentDictionary<UInt32, QuoteRtN> Snapshoot =
            new ConcurrentDictionary<UInt32, QuoteRtN>();

        public static readonly ConcurrentDictionary<UInt32, DateTime> SnapshootUpdateTime =
            new ConcurrentDictionary<UInt32, DateTime>();

        public static readonly ConcurrentDictionary<UInt32, long> SnapshootUpdateDelay =
            new ConcurrentDictionary<UInt32, long>();

        public ConnectPool ConnectPool;
         
        public List<Stkinfo> StockList;

        public List<Stkinfo> FasterStockList = new List<Stkinfo>();

        public static readonly ConcurrentDictionary<TdxConnection, HqLooper> Loopers =
            new ConcurrentDictionary<TdxConnection, HqLooper>();

        public System.Threading.Tasks.Task QueueTask;

        public QueueLooper QueueLooper;

        public List<HqLooper> ErrorHqLoopers = new List<HqLooper>();
        private readonly object _errorLock = new object();

        private static SanpshootService _service;

        public static void Main(string[] args)
        {
            _service = new SanpshootService();
            TaskConfig.RunTask();
            Console.ReadKey();
        }

        public static SanpshootService GetService()
        {
            return _service;
        }

        private SanpshootService()
        {
            InitService();
            InitStockList();

            InitHqLooper();
            EmailSenter.SendEmail("行情服务开启", "行情服务开启");
            //开启TCP服务
            InitTcpClient();
            //维护任务
            
            Console.ReadKey();
        }
        
        /// <summary>
        /// 初始化TCP信道
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void InitTcpClient()
        {
            System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                var serverBase = new ServerBase(10503);
                RemotingBase remotingBase = serverBase.GetTcpInstance();
                remotingBase.OnJsonValueEvent += arg =>
                {
                    switch (arg.TypeId)
                    {
                        //监听获取分时数据
                        case (int)TdxFun.TdxL1Hq_GetMinuteTimeData:
                            var funConnection = ConnectPool.GetFunConnection();
                            var deserializeObject = JsonConvert.DeserializeObject<List<Stkinfo>>(arg.JsonValue);
                            Dictionary<string,List<StkMin>> minuteTimeData = Quote.GetMinuteTimeData(funConnection,deserializeObject);
                            return JsonConvert.SerializeObject(minuteTimeData);
                        case (int)TdxFun.TdxL1Hq_GetAllQuote:
                            var quoteRtNs = Snapshoot.Values.ToList();
                            return JsonConvert.SerializeObject(quoteRtNs);
                        case (int)TdxFun.TdxL1Hq_SetFasterStkList:
                            var stkList = JsonConvert.DeserializeObject<List<Stkinfo>>(arg.JsonValue);
                            FasterStockList.Clear();
                            FasterStockList.AddRange(stkList);
                            foreach (var hqLooper in Loopers.Where(m => "faster".Equals(m.Key.ConnectionTag)).Select(m=>m.Value))
                            {
                                hqLooper.SetStkList(FasterStockList);
                            }
                            return "";
                        default:
                            return "";
                    }
                };
            });
            Thread.Sleep(10000);
            var clientBase = new ClientBase("localhost",10503,"Tdx");
            var tcpInstance = clientBase.GetTcpInstance();
            var serializeObject = JsonConvert.SerializeObject(StockList.GetRange(0,20));
            var sendJson = tcpInstance.SendJson(serializeObject,(int)TdxFun.TdxL1Hq_SetFasterStkList);
        }

        private void InitHqLooper()
        {
            var connectPoolConnections = ConnectPool.Connections;
            var hqLoopers = new List<HqLooper>();
            foreach (var hostItem in Config.GetConfig().BaseMarket.Host)
            {
                var tdxConnections = connectPoolConnections.Where(m => m.Ip.Equals(hostItem.IpAddress)).Where(m=>"base".Equals(m.ConnectionTag)).ToList();
                int partitionSize = StockList.Count / (tdxConnections.Count == 0 ? 1 : tdxConnections.Count) + 1;
                var list = StockList.Partition(partitionSize).ToList();
                for (var i = 0; i < tdxConnections.Count; i++)
                {
                    var tdxConnection = tdxConnections[i];
                    var stockList = list[i];
                    var looper = new HqLooper(tdxConnection, stockList);
                    Loopers.TryAdd(tdxConnection, looper);
                    hqLoopers.Add(looper);
                }
            }

            foreach (var hostItem in Config.GetConfig().FasterMarket.Host)
            {
                var tdxConnections = connectPoolConnections.Where(m => m.Ip.Equals(hostItem.IpAddress)).Where(m => "faster".Equals(m.ConnectionTag)).ToList();
                foreach (var tdxConnection in tdxConnections)
                {
                    var looper = new HqLooper(tdxConnection, FasterStockList);
                    Loopers.TryAdd(tdxConnection, looper);
                    hqLoopers.Add(looper);
                }
            }

            //发生错误的轮训器回调后加入错误列表
            hqLoopers.ForEach(looper =>
            {
                looper.Listener = (connection =>
                {
                    lock (_errorLock)
                    {
                        ErrorHqLoopers.Add(looper);
                    }
                });
                looper.Start();
            });
        }

        public void InitService()
        {
            RedisUtils.GetInstance();
            ConnectPool = ConnectPool.GetInstance();
            InitQueueLooper();
        }

        public void InitQueueLooper()
        {
            QueueLooper = QueueLooper.GetInstance();
            QueueTask = System.Threading.Tasks.Task.Factory.StartNew(() => { QueueLooper.Run(); });
        }

        public void CheckError()
        {
            if (ConnectPool.GetAvailabeConncetions().Count == 0)
            {
                _log.Error("tdxConnections.Count == 0 连接数为0，请检查通达信行情服务是否正常，以及TdxHq.dll是否正常");
                EmailSenter.SendEmail("通达信行情错误", "tdxConnections.Count == 0 连接数为0，请检查通达信行情服务是否正常，以及TdxHq.dll是否正常");
                throw new Exception("connection error");
            }
        }

        public void InitStockList()
        {
            StockList = Quote.TdxGetStkcode(ConnectPool.GetFasterConncetions());
        }
    }
}